
from types import NoneType
from Miranda import RuleVerb,RuleSubject, RuleSetting

import Miranda
import gobject
import gtk
import os


"""
CreateRuleEditor Class manages the behavior of CreateRule Window
"""
class CreateRuleEditor:

    CONFIG_FILE_PATH = "./config.pkl"
        
    def on_window_destroy(self, widget, data=None):
        """
        Destroy the CreateRule window when user click on the close (X) button
        """
        gtk.main_quit()

    def __init__(self, rule=None):
        
       """
       Initialise the CreateRule window
       """
       self.main_screen_observer = None;
       self.glade_file = './CreateRule.glade';            
       self.rule = rule
       self.file_cmp_cmbbox_dict = {}
       self.cmbbox_entry_dict = {}
       self.cmbbox_entry_dict[RuleSubject.B] = 0
       self.cmbbox_entry_dict[RuleSubject.KB] = 1
       self.cmbbox_entry_dict[RuleSubject.MB] = 2

       self.cmbbox_entry_dict[RuleSubject.MINUTE] = 0
       self.cmbbox_entry_dict[RuleSubject.HOUR] = 1
       self.cmbbox_entry_dict[RuleSubject.WEEK] = 2
       self.cmbbox_entry_dict[RuleSubject.MONTH] = 3
       self.cmbbox_entry_dict[RuleSubject.YEAR] = 4

       self.cmbbox_entry_dict[Miranda.IS] = 0
       self.cmbbox_entry_dict[Miranda.IS_NOT] = 1
       self.cmbbox_entry_dict[Miranda.MATCHES_ONE_OF] = 2
       self.cmbbox_entry_dict[Miranda.DOES_NOT_MATCH_ONE_OF] = 3
       self.cmbbox_entry_dict[Miranda.CONTAINS] = 4
       self.cmbbox_entry_dict[Miranda.DOES_NOT_CONTAIN] = 5

       self.cmbbox_entry_dict[Miranda.EQUAL] = 0
       self.cmbbox_entry_dict[Miranda.NOT_EQUAL] = 1
       self.cmbbox_entry_dict[Miranda.GREATER_THAN] = 2
       self.cmbbox_entry_dict[Miranda.LESS_THAN] = 3

       self.cmbbox_entry_dict[Miranda.IS_IN_THE_LAST] = 0     
       self.cmbbox_entry_dict[Miranda.IS_NOT_IN_THE_LAST] = 1
       
       self.cmbbox_entry_dict[RuleVerb.MOVE] = 0     
       self.cmbbox_entry_dict[RuleVerb.COPY] = 1
       self.cmbbox_entry_dict[RuleVerb.RENAME] = 2
       self.cmbbox_entry_dict[RuleVerb.DELETE] = 3
       self.cmbbox_entry_dict[RuleVerb.RECYCLE] = 4
       
       self.cmbbox_entry_dict[Miranda.ALL] = 0
       self.cmbbox_entry_dict[Miranda.ANY] = 1
  
       self.builder = gtk.Builder()
       self.builder.add_from_file(self.glade_file)
        
       self.window = self.builder.get_object("window")       
       self.builder.connect_signals(self)    
       
       self.__populate_condition_cmb_box__();       
       self.__populate_action_cmb_box__();
       self.builder.get_object("okBtn").connect("clicked",lambda save: self.__save_rule__())
       self.builder.get_object("ruleActionCmbBox").connect("changed",lambda x: self.__change_rule_action__())
       self.builder.get_object("cancelBtn").connect("clicked",lambda x: self.__destroy__())
       self.builder.get_object("testBtn").connect("clicked",lambda x: self.__run_test__())
       self.builder.get_object("new_file_name_txtfield").hide();

    def set_edited_rule(self,rule):
              
       self.__create_rule_boxes__(rule)       
                  
       self.builder.get_object("srcFolderLbl").set_text(self.rule.rule_setting.source_folder)
       self.builder.get_object("enabledChkBox").set_active(self.rule.rule_setting.enabled)
       self.builder.get_object("confirmActionChkBox").set_active(self.rule.rule_setting.confirm_action)
       self.builder.get_object("recursiveChkBox").set_active(self.rule.rule_setting.recursive)
       self.builder.get_object("descTxtField").set_text(self.rule.rule_setting.description)
       self.builder.get_object("conditionCmbBox").set_active(self.cmbbox_entry_dict[self.rule.rule_condition])
       self.builder.get_object("ruleActionCmbBox").set_active(self.cmbbox_entry_dict[self.rule.rule_verb.type])       
       self.builder.get_object("new_file_name_txtfield").set_text(self.rule.rule_verb.new_file_name)
       self.builder.get_object("dest_folder").set_current_folder(self.rule.rule_verb.dest_folder)
       self.builder.get_object("overwriteChkBox").set_active(self.rule.rule_verb.overwrite)
       self.builder.get_object("compressChkBox").set_active(self.rule.rule_verb.compression)
    
    def create_new_rule(self,source_folder):
        self.builder.get_object("srcFolderLbl").set_text(source_folder);
        self.__create_rule_boxes__(None)
    
    def set_rule_setting(self, ruleSetting):
        """
        Populate the rule settings field from the provided ruleSetting instance
        """
       
        descTxtField = self.builder.get_object("descTxtField")
        descTxtField.set_text(ruleSetting.description);
        
        enabled_check_box = self.builder.get_object("enabledChkBox");
        enabled_check_box.set_active(ruleSetting.enabled);
        
        confirm_action_check_box = self.builder.get_object("confirmActionChkBox");
        confirm_action_check_box.set_active(ruleSetting.confirm_action);
        
        recursive_check_box = self.builder.get_object("recursiveChkBox");
        recursive_check_box.set_active(ruleSetting.recursive);
        
        source_folder = self.builder.get_object("srcFolderLbl")
        source_folder.set_text(ruleSetting.source_folder);
    
    def __populate_file_cmp_cmb_box__(self, file_cmp_cmb_box):
       """
       Populate the file component combo box with 'Name','Extension','Size','Last Modified Date','Last Opened Date',
       'Created Date'.
       """
       file_cmp_cmb_box.clear();
       
       liststore = gtk.ListStore(gobject.TYPE_STRING)       
       file_cmp_cmb_box.set_model(liststore);
       cell = gtk.CellRendererText()
       file_cmp_cmb_box.pack_start(cell, True)
       file_cmp_cmb_box.add_attribute(cell, 'text', 0)
       file_cmp_cmb_box.append_text(Miranda.FILE_NAME);
       file_cmp_cmb_box.append_text(Miranda.FILE_EXT);
       file_cmp_cmb_box.append_text(Miranda.FILE_SIZE);
       file_cmp_cmb_box.append_text(Miranda.LAST_MOD_DT);
       file_cmp_cmb_box.append_text(Miranda.LAST_OPENED_DT);
       file_cmp_cmb_box.append_text(Miranda.CREATE_DT);
       file_cmp_cmb_box.set_active(0);
       
       self.cmbbox_entry_dict[Miranda.FILE_NAME] = 0
       self.cmbbox_entry_dict[Miranda.FILE_EXT] = 1
       self.cmbbox_entry_dict[Miranda.FILE_SIZE] = 2
       self.cmbbox_entry_dict[Miranda.LAST_MOD_DT] = 3
       self.cmbbox_entry_dict[Miranda.LAST_OPENED_DT] = 4
       self.cmbbox_entry_dict[Miranda.CREATE_DT] = 5
    
    def __populate_criteria_cmb_box__(self, file_cmp_name, criteria_cmb_box):
       """
       populate the criteria drop down list according to the provided file component name
       """
    
       #reset any entry in the combo box if there is any.
       criteria_cmb_box.clear();
       
       liststore = gtk.ListStore(gobject.TYPE_STRING)       
       criteria_cmb_box.set_model(liststore);
       cell = gtk.CellRendererText()
       criteria_cmb_box.pack_start(cell, True)
       criteria_cmb_box.add_attribute(cell, 'text', 0)
       
       if file_cmp_name == Miranda.FILE_NAME or file_cmp_name == Miranda.FILE_EXT:
           criteria_cmb_box.append_text(Miranda.IS)
           criteria_cmb_box.append_text(Miranda.IS_NOT)
           criteria_cmb_box.append_text(Miranda.MATCHES_ONE_OF)
           criteria_cmb_box.append_text(Miranda.DOES_NOT_MATCH_ONE_OF)
           criteria_cmb_box.append_text(Miranda.CONTAINS)
           criteria_cmb_box.append_text(Miranda.DOES_NOT_CONTAIN)          
           #TODO: Append Contains One Of
       elif file_cmp_name == Miranda.FILE_SIZE:
           criteria_cmb_box.append_text(Miranda.EQUAL)
           criteria_cmb_box.append_text(Miranda.NOT_EQUAL)
           criteria_cmb_box.append_text(Miranda.GREATER_THAN)
           criteria_cmb_box.append_text(Miranda.LESS_THAN)          
       elif file_cmp_name == Miranda.LAST_MOD_DT or file_cmp_name == Miranda.LAST_OPENED_DT or file_cmp_name == Miranda.CREATE_DT:             
           criteria_cmb_box.append_text(Miranda.IS_IN_THE_LAST)
           criteria_cmb_box.append_text(Miranda.IS_NOT_IN_THE_LAST)
                        
       criteria_cmb_box.set_active(0);      
         
    def __populate_uom_cmb_box__(self, uom_cmb_box,file_cmp_name):
       
       uom_cmb_box.clear();
       
       liststore = gtk.ListStore(gobject.TYPE_STRING)
       
       uom_cmb_box.set_model(liststore);
       cell = gtk.CellRendererText()
       uom_cmb_box.pack_start(cell, True)
       uom_cmb_box.add_attribute(cell, 'text', 0)
       
       if file_cmp_name == Miranda.FILE_SIZE:
           uom_cmb_box.append_text(RuleSubject.B)
           uom_cmb_box.append_text(RuleSubject.KB)
           uom_cmb_box.append_text(RuleSubject.MB)  
           uom_cmb_box.show()         
       elif file_cmp_name == Miranda.LAST_MOD_DT or file_cmp_name == Miranda.LAST_OPENED_DT or file_cmp_name == Miranda.CREATE_DT:             
           uom_cmb_box.append_text(RuleSubject.MINUTE)
           uom_cmb_box.append_text(RuleSubject.HOUR)  
           uom_cmb_box.append_text(RuleSubject.WEEK)
           uom_cmb_box.append_text(RuleSubject.MONTH)
           uom_cmb_box.append_text(RuleSubject.YEAR)
           uom_cmb_box.show()           
       else:
           uom_cmb_box.hide();    
        
    def __populate_action_cmb_box__(self):        
       liststore = gtk.ListStore(gobject.TYPE_STRING)
       
       rule_action_cmb_box = self.builder.get_object("ruleActionCmbBox")
       rule_action_cmb_box.set_model(liststore);
       cell = gtk.CellRendererText()
       
       rule_action_cmb_box.pack_start(cell, True)
       rule_action_cmb_box.add_attribute(cell, 'text', 0)
       
       rule_action_cmb_box.append_text(RuleVerb.MOVE)
       rule_action_cmb_box.append_text(RuleVerb.COPY)
       rule_action_cmb_box.append_text(RuleVerb.RENAME)
       rule_action_cmb_box.append_text(RuleVerb.DELETE)
       rule_action_cmb_box.append_text(RuleVerb.RECYCLE)
       rule_action_cmb_box.append_text(RuleVerb.OPEN)
    
    def __change_rule_action__(self):
        
        selected_rule_action = self.builder.get_object("ruleActionCmbBox").get_active_text()
        
        if selected_rule_action == RuleVerb.RENAME:
            self.builder.get_object("dest_folder").hide();
            self.builder.get_object("new_file_name_txtfield").show();            
            self.builder.get_object("to_folder_lbl").set_text(":");
            self.builder.get_object("overwriteChkBox").set_sensitive(False);
            self.builder.get_object("compressChkBox").set_sensitive(False);
        elif selected_rule_action == RuleVerb.DELETE or selected_rule_action == RuleVerb.RECYCLE or selected_rule_action == RuleVerb.OPEN:
            self.builder.get_object("dest_folder").hide();
            self.builder.get_object("new_file_name_txtfield").hide();
            self.builder.get_object("to_folder_lbl").set_text("");            
            self.builder.get_object("overwriteChkBox").set_sensitive(False);
            self.builder.get_object("compressChkBox").set_sensitive(False);
        else:
            self.builder.get_object("dest_folder").show();
            self.builder.get_object("new_file_name_txtfield").hide();
            self.builder.get_object("to_folder_lbl").set_text("to folder:");
            self.builder.get_object("overwriteChkBox").set_sensitive(True);
            self.builder.get_object("compressChkBox").set_sensitive(True);
        
    def __populate_condition_cmb_box__(self):
       
       """
       Populate the Condition Combo Box with 'ALL' and 'ANY'
       """
        
       liststore = gtk.ListStore(gobject.TYPE_STRING)
       
       condition_cmb_box = self.builder.get_object("conditionCmbBox")
       condition_cmb_box.set_model(liststore);
       
       cell = gtk.CellRendererText()
       
       condition_cmb_box.pack_start(cell, True)
       condition_cmb_box.add_attribute(cell, 'text', 0)
       condition_cmb_box.append_text(Miranda.ALL);
       condition_cmb_box.append_text(Miranda.ANY);
       condition_cmb_box.set_active(0);
       
    def __create_rule_boxes__(self,rule):
        
        #add 1 rule box with no remove button if there is no existing rule
        if isinstance(rule, NoneType):
            self.__add_rule_box__(False);
            return
        
        if len(rule.rule_subjects) == 0:
           self.__add_rule_box__(False);
           return
            
        #only add a remove button when for the 2nd rule boxes onwards 
        index = 0;
        
        for each_rule_subject in rule.rule_subjects:            
            self.__add_rule_box__(not (index == 0), each_rule_subject)
            index += 1;

    def __file_cmp_selection_changed__(self,file_cmp_cmbbox,criteria_cmb_box,uom_cmb_box):
        #file_cmp_cmbbox = self.file_cmp_cmbbox_dict[file_cmp_cmbbox_index]; 
        self.__populate_criteria_cmb_box__(file_cmp_cmbbox.get_active_text(), criteria_cmb_box)
        self.__populate_uom_cmb_box__(uom_cmb_box,file_cmp_cmbbox.get_active_text())
        
    def __add_rule_box__(self, with_remove_button, rule_subject=None):
        """
        create a rule widgets when user click the '+' button in the rule subject box
        """
        
        #create a new vertical box to contain the drop down list
        box = gtk.HBox(False, 7);
        
        #create the file component drop down listrule_subject.file_component_type
        file_cmp_cmbbox = gtk.combo_box_new_text();
        self.__populate_file_cmp_cmb_box__(file_cmp_cmbbox)
        file_cmp_cmbbox.show();        
        box.pack_start(file_cmp_cmbbox, False, False, 0);
                
        #create the criteria combox box
        criteria_cmb_box = gtk.combo_box_new_text();
        self.__populate_criteria_cmb_box__(Miranda.FILE_NAME, criteria_cmb_box)
        criteria_cmb_box.show();
        box.pack_start(criteria_cmb_box, False, False, 0);
        
        #create the value text field
        entry = gtk.Entry();
        entry.show();
        box.pack_start(entry, False, False, 0);
        
        #create a drop down list for the UOM
        uom_cmbbox = gtk.combo_box_new_text();
        box.pack_start(uom_cmbbox, False, False, 0);
       
        index = len(self.file_cmp_cmbbox_dict)
        self.file_cmp_cmbbox_dict[index] = file_cmp_cmbbox
        #add a change signal to the file component box to change the criteria combo box entries when 
        #user selects different file component name.                    
        file_cmp_cmbbox.connect("changed", lambda x: self.__file_cmp_selection_changed__(file_cmp_cmbbox,criteria_cmb_box,uom_cmbbox));
        
        #create the add button
        add_btn = gtk.Button("+");       
        add_btn.show();
        box.pack_start(add_btn, False, False, 0);        
        
        #Setup the add button signal to add more rule subject combo box when the add button is clicked
        add_btn.connect("clicked", lambda add: self.__add_rule_box__(True));
        
        
        ruleSubjectBox = self.builder.get_object("ruleSubjectBox");
        
        #create the remove button
        if with_remove_button:
            remove_btn = gtk.Button("-");
            remove_btn.show();
            box.pack_start(remove_btn, False, False, 0);
            remove_btn.connect("clicked",lambda remove: ruleSubjectBox.remove(box))
            
        #populate the box with the combo boxes        
        box.show();
        
        #add the rule drop down list into the rule subject box on the main create rule tab screen.        
        ruleSubjectBox.pack_start(box, False, False, 0);
        
        if not isinstance(rule_subject, NoneType):                                
            file_cmp_cmbbox.set_active(self.cmbbox_entry_dict[rule_subject.file_component_type])
            
            if not isinstance(rule_subject.uom, NoneType):                                
                uom_cmbbox.set_active(self.cmbbox_entry_dict[rule_subject.uom])                
                
            entry.set_text(rule_subject.value)
            criteria_cmb_box.set_active(self.cmbbox_entry_dict[rule_subject.criteria])                        
        
        
    
    def __get_rule_from_ui__(self):
        rule = Miranda.Rule();
        rule.rule_condition = self.builder.get_object("conditionCmbBox").get_active_text();
        
        rule_setting = Miranda.RuleSetting();
        rule_setting.description = self.builder.get_object("descTxtField").get_text();
        rule_setting.confirm_action = self.builder.get_object("confirmActionChkBox").get_active();
        rule_setting.enabled = self.builder.get_object("enabledChkBox").get_active();
        rule_setting.recursive = self.builder.get_object("recursiveChkBox").get_active();
        rule_setting.source_folder = self.builder.get_object("srcFolderLbl").get_text();
        
        rule.rule_setting = rule_setting;
              
        rule_criteria_boxes = self.builder.get_object("ruleSubjectBox").get_children();
                

        for each_criteria_box in rule_criteria_boxes[1:len(rule_criteria_boxes)]:
                     
            file_cmp_cmb_box = each_criteria_box.get_children()[0];
            criteria_cmb_box = each_criteria_box.get_children()[1];
            criteria_entry_field = each_criteria_box.get_children()[2];
            
            if len(each_criteria_box.get_children()) > 3 :
                uom_field = each_criteria_box.get_children()[3];
            
            rule_subject = RuleSubject();
            rule_subject.file_component_type = file_cmp_cmb_box.get_active_text();
            rule_subject.criteria = criteria_cmb_box.get_active_text();
            rule_subject.value = criteria_entry_field.get_text();
            if uom_field:
                rule_subject.uom = uom_field.get_active_text();
            
            rule.rule_subjects.append(rule_subject)
               
        rule_verb = RuleVerb();
        rule_verb.new_file_name = self.builder.get_object("new_file_name_txtfield").get_text();
        rule_verb.compression = self.builder.get_object("compressChkBox").get_active();        
        rule_verb.dest_folder = self.builder.get_object("dest_folder").get_current_folder();
        rule_verb.type = self.builder.get_object("ruleActionCmbBox").get_active_text();
        rule_verb.overwrite = self.builder.get_object("overwriteChkBox").get_active();
                
        rule.rule_verb = rule_verb
        
        #user is updating an existing rule
        if not isinstance(self.rule,NoneType):
           rule.isNew = False 
        else:
            #user is creating a new rule
           rule.isNew = True;
           
        return rule;
        
    def __save_rule__(self):
        rule = self.__get_rule_from_ui__();
        
        validation_result = Miranda.validate_rule(rule);
        
        if not isinstance(validation_result, NoneType):
            Miranda.open_msg_dialog(self.window,validation_result)   
            return       

        self.main_screen_observer.save_config(rule);
        
        self.window.destroy();
        
    def __run_test__(self):
        Miranda.do_file_operation(self.__get_rule_from_ui__());
    
    def __destroy__(self):
        self.window.destroy();
        
if __name__ == "__main__":
    
    createRuleEditor = CreateRuleEditor()
    createRuleEditor.window.show()    
    gtk.main()



